package com.powernode.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.powernode.constant.ManagerConstants;
import com.powernode.domain.SysMenu;
import com.powernode.mapper.SysMenuMapper;
import com.powernode.service.SysMenuService;
import com.powernode.util.JSONUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService{

    @Resource
    private SysMenuMapper sysMenuMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 根据用户ID查询菜单集合
     * @param userId
     * @return
     */
    @Override
    public Set<SysMenu> queryUserMenus(Long userId) {
        // 先读取redis , 如果有 直接用 , 如果没有 则 从数据库查
        String menusJsonStr = stringRedisTemplate.opsForValue().get(ManagerConstants.SYS_MENU_PREFIX + userId);
        Set<SysMenu> sysMenus = null;
        if (StringUtils.hasText(menusJsonStr)) {
            // 存在
            // json 转 对象
            List<SysMenu> sysMenusList = JSONObject.parseArray(menusJsonStr, SysMenu.class);
            sysMenus = new HashSet<>(sysMenusList);
        } else {
            // 根据用户id拿到数据 菜单集合
            sysMenus = sysMenuMapper.selectUserMenusByUserId(userId);
            // 将查到的值 , 存入到 redis当中
            stringRedisTemplate.opsForValue().set(ManagerConstants.SYS_MENU_PREFIX + userId , JSONUtils.objToJson(sysMenus), Duration.ofDays(7));
        }
        // 将菜单集合转换为 树结构 , 并返回
        return translateMenusToTree(sysMenus , 0L);
    }

    /**
     * 将菜单集合转换为树结构
     * 方案一 : 已知菜单深度
     * 方案二 : 未知菜单深度
     * @param sysMenus
     * @param pid
     * @return
     */
    private Set<SysMenu> translateMenusToTree(Set<SysMenu> menus, long pid) {
        /*// 方案一
        // 已知深度 <= 2
        Set<SysMenu> roots = menus.stream().filter(m -> m.getParentId().equals(pid)).collect(Collectors.toSet());
        // 遍历根结点
        roots.forEach(r -> {
            // 从菜单集合中过滤出节点的父节点id值与当前根节点的id一致的节点集合
            Set<SysMenu> child = menus.stream().filter(m -> m.getParentId().equals(r.getMenuId())).collect(Collectors.toSet());
            r.setList(child);
        });*/

        // 方案二 : 未知菜单深度
        // 拿到根结点
        Set<SysMenu> roots = menus.stream().filter(m -> m.getParentId().equals(pid)).collect(Collectors.toSet());
        // 递归获取 子结点id集合
        roots.forEach(r -> r.setList(translateMenusToTree(menus, r.getMenuId())));
        return roots;
    }
}
